package service

import (
	"errors"
	"gitee.com/gopher2011/godemo/logger"
	"gitee.com/gopher2011/godemo/server/dao"
	"sync"
)

// 常驻内存数据

var (
	authLocker sync.RWMutex
	Authorities []*dao.Authority

	roleAuthLocker sync.RWMutex
	RoleAuthorities map[int][]int

	roleLocker sync.RWMutex
	Roles []*dao.Role

	nodeRWMutex sync.RWMutex
	// 节点信息
	AllNode []map[string]interface{}
	// 推荐节点
	AllRecommendNodes []map[string][]map[string]interface{}

	catRWMutex sync.RWMutex
	// 资源分类
	AllCategory []*dao.ResourceCategory

	WebsiteSetting *dao.WebsiteSetting

	DefaultAvatars []string

	userSettingLocker sync.RWMutex
	UserSetting map[string]int
)

// 将所有权限加载到内存中;后台修改权限时,重新加载一次
func LoadAuthorities()error{
	authLocker.Lock()
	defer authLocker.Unlock()

	all, err := dao.AuthorityDao.Find()
	if err != nil {
		logger.Errorln("LoadAuthorities authority read fail:",err)
		return err
	}
	for _,item := range all {
		Authorities = append(Authorities,&item)
	}
	logger.Infoln("LoadAuthorities successfully!")
	return nil
}

// 将所有角色拥有的权限加载到内存中;后台加载是,重新加载一次
func LoadRoleAuthorities()error{
	roleAuthLocker.Lock()
	defer roleAuthLocker.Unlock()
	all, err := dao.RoleDao.Find()
	if err != nil {
		logger.Errorln("LoadRoleAuthorities role_authority read fail:", err)
		return err
	}

	// 角色==>权限: 一对多
	for _,item := range all {
		roleId := item.RoleId

		if authorities ,ok := RoleAuthorities[roleId];ok { //获取每一个角色对应的权限Id的集合(即:一个角色对应多条权限记录)
			RoleAuthorities[roleId] = append(authorities,item.Aid)
		}else {
			RoleAuthorities[roleId] = []int{item.Aid}
		}
	}
	logger.Infoln("LoadRoleAuthorities successfully!")
	return nil
}

// 将所有角色加载到内存中;后台修改角色时,重新加载一次
func LoadRoles()error{
	roleLocker.Lock()
	defer roleLocker.Unlock()
	roles,err := dao.RoleDao.FindRoles()
	if err != nil {
		logger.Errorln("LoadRoles role read fail:",err)
		return err
	}

	if len(roles) == 0 {
		logger.Errorln("LoadRoles role read fail: num is 0")
		return errors.New("no role")
	}

	maxRoleId := roles[len(roles)-1].RoleId
	Roles = make([]*dao.Role,maxRoleId)

	// 由于角色不多，而且一般角色id是连续自增的，因此这里以角色id当slice的index
	for _,item := range roles {
		Roles[item.RoleId-1] = &item
	}
	logger.Infoln("LoadRoles successfully!")
	return nil
}

// 将所有 节点信息 加载到内存中：后台修改节点时，重新加载一次
func LoadNodes()error{
	nodeRWMutex.Lock()
	defer nodeRWMutex.Unlock()
	// 如果有 推荐 节点，加载推荐节点
	hasRecommend := loadRecommendNodes()
	if hasRecommend {
		return nil
	}

	nodeList, err := dao.TopicDao.FindTopicNodes()
	if err != nil {
		logger.Errorln("LoadNodes node read fail:", err)
		return err
	}

	nodeNum := len(nodeList)

	tmpNodeList := make(map[int]*dao.TopicNode,nodeNum)
	for _,node := range nodeList {
		tmpNodeList[node.Nid] = &node
	}

	AllNode = make([]map[string]interface{},nodeNum)
	for i,node := range nodeList {
		nodeMap := make(map[string]interface{},5)
		nodeMap["pid"] = node.Parent
		if node.Parent == 0 {
			nodeMap["parent"] = "根节点"
		}else {
			nodeMap["parent"]=tmpNodeList[node.Parent].Name
		}
		nodeMap["nid"] = node.Nid
		nodeMap["logo"]=node.Logo
		nodeMap["name"]=node.Name
		nodeMap["ename"]=node.Ename
		nodeMap["intro"]=node.Introduction
		nodeMap["show_index"]=node.ShowIndex
		nodeMap["ctime"]=node.Ctime
		AllNode[i] = nodeMap
	}
	logger.Infoln("LoadNodes successfully!")
	return nil
}
// 加载推荐节点
func loadRecommendNodes()bool{
	nodeList, err := dao.TopicDao.LoadNodes()
	if err !=nil {
		logger.Errorln("loadRecommendNodes node read fail:", err)
		return false
	}

	if len(nodeList)==0{
		return false
	}

	parentMap := make(map[int]string) //节点Id ==> 节点名
	parentSlice := make([]string,0,20) //存储所有父节点的名称
	sameParent := make(map[string][]map[string]interface{})


	for _,node := range nodeList{
		if node.Parent == 0 {
			parentName := node.Name
			parentMap[node.Id] = parentName
			parentSlice = append(parentSlice,parentName)
		}else {
			parentName := parentMap[node.Parent]
			sameParent[parentName] = append(sameParent[parentName],map[string]interface{}{
				"name":node.TName,
				"ename":node.Ename,
			})
		}
	}

	AllRecommendNodes = make([]map[string][]map[string]interface{},len(parentSlice))

	for i,name := range parentSlice {
		children := sameParent[name]
		AllRecommendNodes[i] = map[string][]map[string]interface{}{
			name:children,
		}
	}
	logger.Infoln("loadRecommendNodes successfully!")
	return true
}

func LoadWebsiteSetting()error{
	list, err := dao.WebsiteSettingDao.SelectTemplate()
	if err != nil {
		logger.Errorln("LoadUserSetting Find fail:", err)
		return err
	}
	WebsiteSetting = &list[0]
	logger.Infoln("LoadWebsiteSetting successfully!")
	return nil
}

func LoadUserSetting()error{
	userSettingLocker.Lock()
	defer userSettingLocker.Unlock()
	list, err := dao.UserSettingDao.SelectTemplate()
	if err != nil {
		logger.Errorln("LoadUserSetting Find fail:", err)
		return err
	}

	UserSetting = make(map[string]int)

	for _,item := range list {
		UserSetting[item.Key] = item.Value
	}
	logger.Infoln("LoadUserSetting successfully!")
	return nil
}

func LoadDefaultAvatar()error {
	list, err := dao.UserDao.FindDefaultAvatar()
	if err != nil {
		logger.Errorln("LoadDefaultAvatar Find fail:", err)
		return err
	}
	DefaultAvatars = make([]string,len(list))
	for i,item := range list {
		DefaultAvatars[i]=item.Filename
	}
	logger.Infoln("LoadDefaultAvatar successfully!")
	return nil
}

// 获取单个节点名
func GetNodeName(nid int)string{
	nodeRWMutex.Lock()
	defer nodeRWMutex.Unlock()
	if len(AllRecommendNodes)>0{
		one, err := dao.TopicDao.FindOne(nid)
		if err != nil {
			logger.Errorln("TopicNodeLogic FindOne error:", err, "nid:", nid)
		}
		return one.Name
	}
	for _, node := range AllNode {
		if node["nid"].(int) == nid {
			return node["name"].(string)
		}
	}
	return ""
}
// 通过ename获取单个节点 map中 key 是字段名,value则是:对应字段名的具体值.
func GetNodeByEname(ename string)map[string]interface{}{
	nodeRWMutex.Lock()
	defer nodeRWMutex.Unlock()
	if len(AllRecommendNodes)>0{
		node, err := dao.TopicDao.FindByEname(ename)
		if err != nil {
			logger.Errorln("TopicNodeLogic FindByEname error:", err, "ename:", ename)
		}
		return map[string]interface{}{
			"ename":      node.Ename,
			"name":       node.Name,
			"pid":        node.Parent,
			"nid":        node.Nid,
			"logo":       node.Logo,
			"show_index": node.ShowIndex,
			"intro":      node.Introduction,
		}
	}

	for _,node := range AllNode {
		if node["ename"].(string) == ename {
			return node
		}
	}
	return nil
}

// 通过 ename 获得 nid
func GetNidByEname(ename string)int {
	nodeRWMutex.Lock()
	defer nodeRWMutex.Unlock()

	if len(AllRecommendNodes)>0{
		one, err := dao.TopicDao.FindByEname(ename)
		if err != nil {
			logger.Errorln("TopicNodeLogic FindByEname error:", err, "ename:", ename)
		}
		return one.Nid
	}
	for _,node := range AllNode {
		if node["ename"].(string) == ename {
			return node["nid"].(int)
		}
	}
	return 0
}

// 获取单个节点信息
func GetNode(nid int)map[string]interface{}{
	nodeRWMutex.Lock()
	defer nodeRWMutex.Unlock()
	if len(AllRecommendNodes)>0{
		node,err := dao.TopicDao.FindOne(nid)
		if err != nil {
			logger.Errorln("TopicNodeLogic FindOne error:", err, "nid:", nid)
		}
		return map[string]interface{}{
			"ename":      node.Ename,
			"pid":        node.Parent,
			"name":       node.Name,
			"nid":        node.Nid,
			"logo":       node.Logo,
			"intro":      node.Introduction,
			"show_index": node.ShowIndex,
		}
	}
	for _,node := range AllNode{
		if node["nid"].(int) == nid {
			return node
		}
	}
	return nil
}
// 获取多个节点信息
func GetNodesByNids(nids []int)map[int]*dao.TopicNode{
	nodeRWMutex.Lock()
	defer nodeRWMutex.Unlock()
	if len(AllRecommendNodes)>0 {
		list, err := dao.TopicDao.FindByNids(nids)
		if err != nil {
			logger.Errorln("TopicNodeLogic FindByNids error:", err, "nids:", nids)
		}
		nodeList := make(map[int]*dao.TopicNode,0)
		for _,v := range list {
			nodeList[v.Nid] = &v
		}
		return nodeList
	}

	nodes := make(map[int]*dao.TopicNode,len(nids))
	for _,nid := range nids {
		for _,node := range AllNode{
			if node["nid"].(int) == nid {
				nodes[nid] = &dao.TopicNode{
					Nid: nid,
					Name: node["name"].(string),
					Ename: node["ename"].(string),
					ShowIndex: node["show_index"].(bool),
				}
			}
		}
	}
	return nodes
}

// 获取某个父节点下最多num个子节点
func GetChildrenNode(parentId,num int)[]interface{}{
	nids := make([]interface{},0,num)

	if len(AllRecommendNodes)>0{
		nodeList,err := dao.TopicDao.FindByParent(parentId,num)
		if err != nil {
			logger.Errorln("TopicNodeLogic FindByParent error:", err, "parent:", pid)
		}
		for _,node := range nodeList {
			nids = append(nids,node.Nid)
		}
		return nids
	}
	for _,node := range AllNode {
		if node["pid"].(int) == parentId {
			nids = append(nids,node["nid"])
			if len(nids) == num {
				break
			}
		}
	}
	return nids
}

// 将 node组织成一定形式方便前端展示
func GenNodes()[]map[string][]map[string]interface{}{
	if len(AllRecommendNodes)>0{
		return AllRecommendNodes
	}

	sameParent := make(map[string][]map[string]interface{})
	allParentNodes := make([]string,0,8)
	for _, node := range AllNode {
		if node["pid"].(int) != 0 {
			if len(sameParent[node["parent"].(string)]) == 0 {
				sameParent[node["parent"].(string)] = []map[string]interface{}{node}
			} else {
				sameParent[node["parent"].(string)] = append(sameParent[node["parent"].(string)], node)
			}
		} else {
			allParentNodes = append(allParentNodes, node["name"].(string))
		}
	}
	nodes := make([]map[string][]map[string]interface{}, 0, len(allParentNodes))
	for _, parent := range allParentNodes {
		tmpMap := make(map[string][]map[string]interface{})
		tmpMap[parent] = sameParent[parent]
		nodes = append(nodes, tmpMap)
	}
	logger.Debugf("%v\n", nodes)
	return nodes
}

// 将所有资源分类信息加载到内存中;后台修改时,重新加载一次
func LoadCategories()(err error){
	catRWMutex.Lock()
	defer catRWMutex.Unlock()
	list, err := dao.ResourceDao.Find()
	if err != nil {
		logger.Errorln("LoadCategories category read fail:", err)
		return
	}
	for _,item := range list {
		AllCategory = append(AllCategory,&item)
	}
	logger.Infoln("LoadCategories successfully!")
	return
}


